<script setup lang="ts">
import { reactive, ref, type Ref } from 'vue'
import { ScrollView } from '../../scroll-view'
import type { FloatPaneHolder, FloatPaneOptions } from './types'
import { floatPaneManager } from './manager'
import { useFloatPaneBBox } from './utils'

type Props = {
  showDock: boolean
  dockIcon?: string
  hidable: boolean
  title: string
  padding: number[]
}

const props = withDefaults(defineProps<Props>(), {
  showDock: false,
  dockIcon: 'mas-icon-list',
  hidable: false,
  padding: () => [10, 10, 10, 10],
  title: ''
})

interface FloatPane {
  handleClose?: () => boolean
  handleCloseAsync?: () => boolean
}

const container = ref<HTMLElement>() as Ref<HTMLElement>

const { initBBox, bBox } = useFloatPaneBBox(props, container)

const panes = ref() as Ref<FloatPane[]>

interface FloatPaneHolderX extends FloatPaneHolder {
  contentVisible: boolean
}

const holders = reactive<FloatPaneHolderX[]>([])

function _onDockBtn(h: FloatPaneHolder) {
  if (!h.visible || !h.active) {
    _activePane(h)
  } else if (props.hidable) {
    _hidePane(h)
  }
}

function _updateTitle(h: FloatPaneHolder, title: string) {
  h.name = title
}

function _closePaneIndexed(idx: number) {
  if (idx < 0 || idx >= holders.length) {
    return
  }
  const h = holders.splice(idx, 1)[0]
  floatPaneManager.closePane(h)
}

function _activePane(h: FloatPaneHolder) {
  floatPaneManager.activePane(h)
}

function _hidePane(h: FloatPaneHolder) {
  floatPaneManager.hidePane(h)
}

function _startDrag(h: FloatPaneHolder, evt: MouseEvent) {
  floatPaneManager.dragPane(h, bBox, evt)
}

async function _onCloseBtn(idx: number) {
  if (idx < 0 || idx >= holders.length) {
    return
  }
  const p = panes.value!![idx]
  if (p.handleClose) {
    if (p.handleClose()) {
      _closePaneIndexed(idx)
    }
    return
  }
  if (!p.handleCloseAsync) {
    _closePaneIndexed(idx)
    return
  }

  try {
    await p.handleCloseAsync()
    _closePaneIndexed(idx)
  } catch (e) {
    // console.log(e)
  }
}

function openPane(opt: FloatPaneOptions) {
  const h = floatPaneManager.openPane(opt, initBBox, props.hidable)
  h.contentVisible = true
  holders.push(h)
}

function closePane(f: (opts: FloatPaneOptions) => boolean): boolean {
  let idx = 0
  for (const h of holders) {
    if (f(h)) {
      _closePaneIndexed(idx)
      return true
    }
    idx++
  }
  return false
}

function activePane(f: (opts: FloatPaneOptions) => boolean): boolean {
  for (const h of holders) {
    if (f(h)) {
      _activePane(h)
      return true
    }
  }
  return false
}

function activeOrOpenPane(key: string, f: () => Omit<FloatPaneOptions, 'key'>) {
  if (activePane((o) => o.key === key)) {
    return
  }
  openPane(Object.assign({ key }, f()))
}

function hidePane(f: (opts: FloatPaneOptions) => boolean): boolean {
  for (const h of holders) {
    if (f(h)) {
      _hidePane(h)
      return true
    }
  }
  return false
}

defineExpose({
  openPane,
  activePane,
  hidePane,
  closePane,
  activeOrOpenPane
})
</script>
<template>
  <div class="float-pane-container" ref="container">
    <template v-if="showDock">
      <div class="float-pane-dock">
        <button :class="`icon-button is-white ${dockIcon}`" />
        <div class="float-pane-list">
          <div v-if="title" class="float-pane-list-heading">{{ title }}</div>
          <ScrollView>
            <div
              v-for="h in holders"
              :key="`${h.key}-title`"
              class="float-pane-list-item"
              @click="_onDockBtn(h)"
            >
              <i v-if="h.icon" :class="h.icon" />
              <span>{{ h.name }}</span>
            </div>
          </ScrollView>
        </div>
      </div>
      <div
        v-for="(h, idx) in holders"
        v-show="h.visible"
        :key="h.key"
        class="pane float-pane"
        :class="{ 'is-active': h.active }"
        :style="{ 'z-index': h.zIndex, left: h.left + 'px', top: h.top + 'px' }"
        @mousedown="_activePane(h)"
      >
        <div class="pane-heading" @mousedown="_startDrag(h, $event)">
          <div class="pane-title">
            <i v-if="h.icon" :class="h.icon" />
            {{ h.name }}
          </div>
          <div class="pane-tool">
            <i v-if="h.hidable" class="mas-icon-min" @click="_hidePane(h)" />
            <i class="mas-icon-close" @click="_onCloseBtn(idx)" />
          </div>
        </div>
        <component
          :is="h.component"
          ref="panes"
          v-bind="h.props"
          v-on="h.events"
          @title="_updateTitle(h, $event)"
          @close="_closePaneIndexed(idx)"
          @hide="_hidePane(h)"
        />
      </div>
    </template>
    <template v-else>
      <div
        v-for="(h, idx) in holders"
        v-show="h.visible"
        :key="h.key"
        class="pane float-pane"
        :class="{ 'is-active': h.active }"
        :style="{ 'z-index': h.zIndex, left: h.left + 'px', top: h.top + 'px' }"
        @mousedown="_activePane(h)"
      >
        <div class="pane-heading" @mousedown="_startDrag(h, $event)">
          <div class="pane-title">
            <i v-if="h.icon" :class="h.icon" />
            {{ h.name }}
          </div>
          <div class="pane-tool">
            <template v-if="h.hidable">
              <template v-if="h.contentVisible">
                <i class="mas-icon-min" @click="h.contentVisible = false" />
                <i class="mas-icon-close" @click="_onCloseBtn(idx)" />
              </template>
              <i v-else class="mas-icon-add" @click="h.contentVisible = true" />
            </template>
            <i v-else class="mas-icon-close" @click="_onCloseBtn(idx)" />
          </div>
        </div>
        <component
          v-show="h.contentVisible"
          :is="h.component"
          ref="panes"
          v-bind="h.props"
          v-on="h.events"
          @title="_updateTitle(h, $event)"
          @close="_closePaneIndexed(idx)"
          @hide="_hidePane(h)"
        />
      </div>
    </template>
  </div>
</template>
